﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;

namespace Milan.Deploy
{
	/// <summary>
	/// You can create only one instance of this application,
	/// which can run, depending on the startup mode of the command line parameters, one or more
	/// internal services.  All applications in Milan are really just one or more internal services.
	/// </summary>
	public class Application : IDisposable
	{
		/// <summary>
		/// Which type of internal service it is.
		/// </summary>
		public enum Type { ConsoleBlocking, Gui, Service, BackgroundWorker };
		public enum TriggerType { RunAlways, Fallback, FirstWord, Empty };
		public Application(string[] args = null)
		{
			m_current = this;
			m_mainAppAlreadyStarted = false;
			m_args = args;
			m_internalScanners = new List<Scanner>();
#if DEBUG
			Settings.CompanyMachine.SetValue("IsDevMachine", "true");
#endif
		}
		public void Dispose()
		{
			int exitCode = 0;
			foreach (var service in m_internalScanners)
			{
				service.Stop();
				if (service.ReturnsExitCode)
					exitCode = service.ExitCode;
			}
		}
		public int ExitCode { get; set; }
		/// <summary>
		/// Terminate all the internal services and the application.
		/// It takes the exit code from the service which is marked to return such an exit code.
		/// </summary>
		public void Quit()
		{
			Dispose();
			Environment.Exit(ExitCode);
		}
		private List<Scanner> m_internalScanners;
		public void RunService(Scanner internalService, Type type = Type.ConsoleBlocking, TriggerType triggerType = TriggerType.Empty, string parameter = null)
		{
			bool m_start = false;
			if (type == Type.BackgroundWorker)	// Background workers always start.
				m_start = true;
			else if(!m_mainAppAlreadyStarted)
			{
				if (triggerType == TriggerType.FirstWord && m_args != null && m_args.Length>0 && parameter == m_args[0])
					m_start = true;
				else if (triggerType == TriggerType.Empty && (m_args==null || m_args.Length == 0))
					m_start = true;
				else if (triggerType == TriggerType.Fallback)
					m_start = true;
				if (m_start)
					m_mainAppAlreadyStarted = true;
			}
			if (m_start)
			{
				if (internalService.OnStart(m_args))
				{
					internalService.IsRunning = true;
					m_internalScanners.Add(internalService);
				}
			}
		}
		private bool m_mainAppAlreadyStarted;
		private string[] m_args;
		public static Application Current
		{
			get
			{
				if (m_current == null)
					m_current = new Application();
				return m_current;
			}
		}
		private static Application m_current;
		public static Package ThisPackage { get; set; }
		/// <summary>
		/// Forces the product to check for an update, download, install it and then return false if it is successful.
		/// </summary>
		/// <returns>Returns true if the product was updated</returns>
		public bool UpgradeNow()
		{
			bool returns = false;
			try {
				Client client = new Client();
				client.UpgradeNow();
			}
			catch (Exception)
			{
				returns = true;
			}
			return returns;
		}
	}
}
